﻿namespace WPForms.Phone
{
    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using PhoneUtils.Services;
    using WPForms.Common.Services;
    using WPForms.Phone.Services;

    /// <summary>
    /// Abstract class wich has to be subclassed in WIndows Phone applications to use the framework.
    /// </summary>
    public abstract class Bootstrapper
    {
        /// <summary>
        /// Gets the connection string used to access the database.
        /// The default value is "isostore:/FormsDB.sdf".
        /// </summary>
        public virtual string ConnectionString
        {
            get
            {
                return "isostore:/FormsDB.sdf";
            }
        }

        /// <summary>
        /// Runs the bootstrapper. Calls the following methods in the given order:
        /// 1. CreateContainer
        /// 2. RegisterViewModelMaps
        /// 3. AddFormDescriptions
        /// 4. RegisterNavigationService
        /// 5. RegisterDataAccess
        /// 6. RegisterFormStore
        /// 7. RegisterViewModels
        /// 8. AddResources.
        /// 9. AddViewModelLocatorToResources.
        /// </summary>
        /// <param name="rootFrame">The current phone application's root frame instance.</param>
        public void Run(Microsoft.Phone.Controls.PhoneApplicationFrame rootFrame)
        {
            this.CreateContainer();

            var viewModelMap = new ViewModel.ViewModelMap();
            ContainerLocator.Current.Register<ViewModel.ViewModelMap>(viewModelMap);
            this.RegisterViewModelMaps(viewModelMap);

            // Create and register our form description collection
            var formDescriptionCollection = new WPForms.Common.Model.FormDescriptionCollection();
            ContainerLocator.Current.Register<WPForms.Common.Model.FormDescriptionCollection>(formDescriptionCollection);
            this.AddFormDescriptions(formDescriptionCollection);

            this.RegisterNavigationService(rootFrame);
            this.RegisterDataAccess();
            this.RegisterFormStore();
            this.RegisterViewModels();
            this.AddResources();
            this.AddViewModelLocatorToResources();

            ContainerLocator.Current.Register<Bootstrapper>(this);
        }

        /// <summary>
        /// Creates and sets a new Funq container as current container.
        /// </summary>
        protected virtual void CreateContainer()
        {
            // Create a new Funq container
            ContainerLocator.SetContainer(new Funq.Container());
        }

        /// <summary>
        /// Registers the <see cref="INavigationService"/> implementation to use.
        /// </summary>
        /// <param name="rootFrame">The current phone application's root frame instance.</param>
        protected virtual void RegisterNavigationService(Microsoft.Phone.Controls.PhoneApplicationFrame rootFrame)
        {
            // Create and register the navigation service
            ContainerLocator.Current.Register<INavigationService>(c => new ApplicationFrameNavigationService(rootFrame));
        }

        /// <summary>
        /// Override this method to register additional view model maps.
        /// The base implementation registers the PictureAttachment and the GeoLocation view models.
        /// </summary>
        /// <param name="viewModelMap">The view model map.</param>
        protected virtual void RegisterViewModelMaps(ViewModel.ViewModelMap viewModelMap)
        {
            viewModelMap.Register<WPForms.Common.Model.PictureAttachment, WPForms.Phone.ViewModel.PictureAttachmentViewModel>();
            viewModelMap.Register<WPForms.Common.Model.GeoLocation, WPForms.Phone.ViewModel.GeoLocationViewModel>();
        }

        /// <summary>
        /// If no view model locator is added to the application resources adds the default locator.
        /// The resource key is ViewModelLocator.
        /// </summary>
        protected virtual void AddViewModelLocatorToResources()
        {
            if (Application.Current.Resources["ViewModelLocator"] == null)
            {
                Application.Current.Resources.Add("ViewModelLocator", new ViewModel.ViewModelLocatorBase());
            }
        }

        /// <summary>
        /// Registers the <see cref="DataAccess.IDataAccess"/> implementation.
        /// </summary>
        protected virtual void RegisterDataAccess()
        {
            ContainerLocator.Current.Register<DataAccess.IDataAccess>(new DataAccess.SqlCeDataAccess(this.ConnectionString));
        }

        /// <summary>
        /// Registers the <see cref="WPForms.Common.Services.IFormStore"/> implementation to use.
        /// </summary>
        protected virtual void RegisterFormStore()
        {
            ContainerLocator.Current.Register<Common.Services.IFormStore>(
                c => new Services.SqlCeFormStore(
                    c.Resolve<WPForms.Phone.DataAccess.IDataAccess>(),
                    c.Resolve<WPForms.Common.Model.FormDescriptionCollection>()));
        }

        /// <summary>
        /// Registers the view models used by the framework.
        /// </summary>
        protected virtual void RegisterViewModels()
        {
            ContainerLocator.Current.Register<ViewModel.FormViewModel>(
                c => new ViewModel.FormViewModel(c.Resolve<INavigationService>(), c.Resolve<WPForms.Common.Services.IFormStore>()));
            ContainerLocator.Current.Register<ViewModel.FormCollectionViewModel>(
                c => new ViewModel.FormCollectionViewModel(c.Resolve<WPForms.Common.Services.IFormStore>(), c.Resolve<INavigationService>()));
            ContainerLocator.Current.Register<ViewModel.CreateFormViewModel>(
                c => new ViewModel.CreateFormViewModel(
                    c.Resolve<WPForms.Common.Services.IFormStore>(),
                    c.Resolve<WPForms.Common.Model.FormDescriptionCollection>(),
                    c.Resolve<INavigationService>()));
        }

        /// <summary>
        /// Adds the following resource dictionaries to the application's resources: DataTemplates, Converters, Templates.
        /// </summary>
        protected virtual void AddResources()
        {
            // add datatemplates and converters
            Application.Current.Resources.MergedDictionaries.Add(
                new ResourceDictionary() { Source = new Uri("/WPForms.Phone;component/Resources/DataTemplates.xaml", UriKind.Relative) });
            Application.Current.Resources.MergedDictionaries.Add(
                new ResourceDictionary() { Source = new Uri("/WPForms.Phone;component/Resources/Converters.xaml", UriKind.Relative) });
            Application.Current.Resources.MergedDictionaries.Add(
                new ResourceDictionary() { Source = new Uri("/WPForms.Phone;component/Resources/Templates.xaml", UriKind.Relative) });
        }

        /// <summary>
        /// Implementors have to provide form descriptions for all available forms in the application.
        /// </summary>
        /// <param name="descriptionCollection">The description collection.</param>
        protected abstract void AddFormDescriptions(WPForms.Common.Model.FormDescriptionCollection descriptionCollection);
    }
}
